package cn.wizzer.app.crown.modules.services.impl.result;

import cn.wizzer.app.crown.commons.util.DateUtil;
import cn.wizzer.app.crown.modules.models.CrownConfig;
import cn.wizzer.app.crown.modules.models.CrownMatch;
import cn.wizzer.app.crown.modules.models.CrownSubResult;
import cn.wizzer.app.crown.modules.models.constant.CrownConstant;
import cn.wizzer.app.crown.modules.models.enums.MatchTypeEnum;
import cn.wizzer.app.crown.modules.models.enums.SubResultEnum;
import cn.wizzer.app.crown.modules.services.CrownConfigService;
import cn.wizzer.app.crown.modules.services.CrownMatchService;
import cn.wizzer.app.crown.modules.services.CrownSubResultService;
import cn.wizzer.app.crown.modules.services.result.BKMatchResultService;
import cn.wizzer.app.sys.modules.services.SysParamService;
import cn.wizzer.framework.base.service.BaseServiceImpl;
import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.dubbo.config.annotation.Service;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Dao;
import org.nutz.integration.jedis.RedisService;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.log.Log;
import org.nutz.log.Logs;

import java.util.ArrayList;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


@IocBean(args = {"refer:dao"})
@Service(interfaceClass = BKMatchResultService.class)
public class BKMatchResultServiceImpl extends BaseServiceImpl<CrownMatch> implements BKMatchResultService {

    public BKMatchResultServiceImpl(Dao dao) {
        super(dao);
    }

    private static final Log log = Logs.get();


    @Inject
    private RedisService redisService;
    @Inject
    private CrownMatchService matchService;
    @Inject
    private CrownSubResultService subResultService;
    @Inject
    @Reference(retries = 0, timeout = 500000)
    private CrownConfigService crownConfigService;
    @Inject
    @Reference
    private SysParamService sysParamService;

    private static final Pattern FULL_SCORE_REGX = Pattern.compile("<td class=\"\">([\\s\\S]*?)</td>");

    private static final Pattern NUMBER_REGX = Pattern.compile("^\\d+$");

    @Override
    public void crawler(CrownMatch match, CrownConfig crownConfig) {
        String[] resultArray = this.getData(match, crownConfig);
        if (resultArray == null) {
            this.sendEmail(match);
            return;
        }
        // 爬取篮球进球数
        this.goalsNum(match, resultArray);
        // 更新赛果
        matchService.updateMatchResult(match, "task");
    }



    /**
     * 给管理员发送邮件
     * @param match
     */
    private void sendEmail(CrownMatch match) {
        // 开赛时间(美东)转系统时间
        Date date = DateUtil.timeZoneConvert(match.getDateTime(), "America/New_York", TimeZone.getDefault().getID());
        if (null == date) {
            log.error("爬取赛果发送邮件失败,转换date为null,match:" + match);
            return;
        }
        long matchTime = date.getTime();
        long l = (System.currentTimeMillis() - matchTime) / 1000;
        // 超过赛事时间2小时 4小时 6小时发送邮件
        if ((l >= 3600 * 2 && l <= 3600 * 2.5) || (l >= 3600 * 4 && l <= 3600 * 4.5) || (l >= 3600 * 6 && l <= 3600 * 6.5)) {
            log.info("赛果爬取失败发送邮件。开赛时间已过：" + l + "s");
            sysParamService.sendEmail("3412995626@qq.com","赛果获取不到",
                    "mid：" + match.getMid() + "。开赛时间已过：" + l + "s" + "。位置：hello");
        }
    }


    /**
     * 请求皇冠并检验数据
     *
     * @param match
     * @param crownConfig
     * @return
     */
    private String[] getData(CrownMatch match, CrownConfig crownConfig) {
        // 66.133.86.54/app/member/account/result/BK_result_new.php?uid=hgjs86j5m22923423l266779&gtype=BK&game_id=3421049&langx=zh-cn
        String tailUrl = "/app/member/account/result/BK_result_new.php?uid=" + crownConfig.getUid()
                + "&gtype=BK&game_id=" + match.getMid() + "&langx=" + CrownConstant.LANGX;
        String body = crownConfigService.getCrownData(tailUrl, crownConfig, CrownConstant.RE_TRY_TIMES);
        // 检测账号被登出
        if (crownConfigService.checkLogout(body, crownConfig)) {
            // 重试登录(包括重试三次、自动请求新地址)
//            crownConfigService.loginHg(crownConfig);
//            // 如果登录成功 重新请求数据
//            if (!crownConfig.isLogout()) {
//                this.crawler(match, crownConfig);
//                return;
//            }
            return null;
        }
        // body是空，监测到皇冠维护都return
        if (Strings.isBlank(body)) {
            log.error("爬取篮球赛果失败，body为空");
            return null;
        } else if (crownConfigService.checkMaintain(body, crownConfig)) {
            return null;
        }
        // 截取有效部分
        body = body.replaceAll("\n", "").trim();
        body = body.substring(body.indexOf("<tr class=\"acc_cont_tr\""),
                body.lastIndexOf("</table>"));
        // 没有赛果数据时，页面上联赛、队伍名也是存在的，比分会显示'-'。所以要去判断全场比分是否包含'-'。
        Matcher matcher = FULL_SCORE_REGX.matcher(body.split("全场")[1]);
        if (matcher.find()) {
            String fullScore = matcher.group(1);
            if ("-".equals(fullScore)) {
                return null;
            }
        } else {
            log.error("赛果数据未知格式，body:" + body);
            return null;
        }
        log.info("开始解析篮球赛事赛果, mid:" + match.getMid());
        // 否则赛果存在，替换指定的标签，方便处理
        body = body.replaceAll("<td class=\"acc_cont_bold\">",
                "<td>").replaceAll("<td class=\"\">", "<td>");
        return body.split("<tr class=\"acc_cont_tr\"");
    }





    /**
     * 进球数爬取
     *
     * @param match       CrownMatch对象。目前对象中的主客队比分属性，在结算中有用到
     * @param resultArray 数据源
     */
    @Aop(TransAop.REPEATABLE_READ)
    private void goalsNum(CrownMatch match, String[] resultArray) {
        ArrayList<CrownSubResult> subResults = new ArrayList<>();
        String hInBall, cInBall;
        for (int i = 0; i < resultArray.length; i++) {
            CrownSubResult subResult = new CrownSubResult();
            subResult.setMatchId(match.getId());
            subResult.setGameType(MatchTypeEnum.BASKETBALL);
            subResult.setType(SubResultEnum.GOALS_NUM);
            String result = resultArray[i];
            // split后第一条数据跳过
            if (Strings.isBlank(result)) {
                continue;
            }
            // 比赛阶段(第一节、第二节、全场、半场...)
            String stage = result.substring(result.indexOf("<td class=\"acc_cont_name\">") + 26, result.indexOf("</td>"));
            subResult.setTag("NO" + i);
            subResult.setRemark(stage);
            result = result.substring(result.indexOf("</td>") + 5);
            // 该阶段主队得分
            hInBall = result.substring(result.indexOf("<td>") + 4, result.indexOf("</td>"));
            subResult.setResultH(hInBall);
            result = result.substring(result.indexOf("</td>") + 5);
            // 该阶段客队得分
            cInBall = result.substring(result.indexOf("<td>") + 4, result.indexOf("</td>"));
            subResult.setResultC(cInBall);
            // 判断腰斩
            if (hInBall.contains("腰斩") || cInBall.contains("腰斩")) {
                match.setIsCut(true);
            }
            // 上下半场比分存入主表match中
            if ("上半场".equals(stage)) {
                match.setMbInBallHf(hInBall);
                match.setTgInBallHf(cInBall);
            } else if ("全场".equals(stage)) {
                match.setMbInBall(hInBall);
                match.setTgInBall(cInBall);
                match.setIsHalfGone(true);
                // 如果比分不是数字，并且不是‘腰斩’，则赛事状态为other(这个判断需要在处理全场比分时判断，因为加时赛比分很多都是非数字)
                if (!NUMBER_REGX.matcher(hInBall).find() && !match.getIsCut()) {
                    match.setStage(CrownConstant.OTHER);
                } else {
                    match.setStage(CrownConstant.FINISHED);
                }
            }
            subResults.add(subResult);
        }
        match.setSubResults(subResults);
    }
}
